/*
* Copyright 2011 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/
package org.etherframework.mediation.core
{
	import flash.display.Sprite;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	
	import org.etherframework.mediation.manager.IMediationManager;
	import org.etherframework.mediation.manager.MediationManager;
	
	public final class BunchHelper
	{
		private var _owner:MediationManager;
		private var _classes:Array;
		private var _bunch:uint;
		private var _dispatcher:IEventDispatcher;
		private var _frameDispatcher:IEventDispatcher;
		private var _total:uint = 0;
		private var _counter:uint = 0;
		
		public function BunchHelper(owner:MediationManager, bunch:uint)
		{
			_owner = owner;
			_bunch = bunch;
		}
		
		public function prepare(classes:Array):IEventDispatcher
		{
			if (!(classes && classes.length))
				throw ArgumentError("Argument classes:Array can not be null or empty.");
			
			_dispatcher = new EventDispatcher();
			_frameDispatcher = new Sprite();
			_classes = classes;
			_total = _classes.length % _bunch;
			
			next();
			
			return _dispatcher;
		}
		
		private function next():void
		{
			if (!_classes.length)
			{
				complete();
				return;
			}
			
			const classes:Array = _classes.splice(0, Math.min(_bunch, _classes.length));
			const dispatcher:IEventDispatcher = _owner.prepareClasses(classes);
			
			dispatcher.addEventListener(Event.COMPLETE, completeHandler);
			dispatcher.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			dispatcher.addEventListener(ErrorEvent.ERROR, errorHandler);
		}
		
		private function complete():void
		{
			_dispatcher.dispatchEvent(new Event(Event.COMPLETE));
		}
		
		private function completeHandler(event:Event):void
		{
			removeListeners(IEventDispatcher(event.target));
			_frameDispatcher.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
		}
		
		private function errorHandler(event:Event):void
		{
			removeListeners(IEventDispatcher(event.target));
			_dispatcher.dispatchEvent(event);
		}
		
		private function enterFrameHandler(event:Event):void
		{
			event.target.removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
			
			const evt:ProgressEvent = new ProgressEvent(ProgressEvent.PROGRESS, 
				false, false, ++_counter, _total);
			_dispatcher.dispatchEvent(evt);
			
			next();
		}
		
		private function removeListeners(dispatcher:IEventDispatcher):void
		{
			dispatcher.removeEventListener(Event.COMPLETE, completeHandler);
			dispatcher.removeEventListener(IOErrorEvent.IO_ERROR, errorHandler);
			dispatcher.removeEventListener(ErrorEvent.ERROR, errorHandler);
		}
	}
}